#include <iostream>
using namespace std;

#include "axml.h"
#include "..\\util.h"

#define MEMSET(buf, size)		memset(buf, 0, size)
#define TYPECAST(type, var)		((type)var)
#define TYPE_SIZE(type)			sizeof(type)
#define VAR_TYPECAST(is_true, type_a, type_b, var) (is_true ? (type_a)var : (type_b)var)

#define LOG_BUFFER_SIZE		512
#define ATTR_BUFFER_SIZE	128
#define MAX_TABLE_COUNT		10
#define MAX_STRING_LEN		32767

const char* XML_HEADER = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
static float RADIX_MULTS[] = { 0.00390625F,3.051758E-005F,1.192093E-007F,4.656613E-010F };
static char* DIMENSION_UNITS[8] = { "px","dip","sp","pt","in","mm","","" };

FILE* pLog = NULL;
bool g_is_arsc = false;
char g_log_buf[LOG_BUFFER_SIZE] = { '\0' };
char g_attr_buf[ATTR_BUFFER_SIZE] = { '\0' };
char g_table_buf[MAX_TABLE_COUNT] = { '\0' };
bool g_is_utf8;
uint8_t* g_global_chunk = NULL;
uint8_t* g_type_chunk = NULL;
uint8_t* g_key_chunk = NULL;
uint32_t g_string_pool_seq = 0;
uint32_t g_global_string_count = 0;
uint32_t g_type_string_count = 0;
uint32_t g_key_string_count = 0;
uint32_t g_file_size;
void* g_prefix;
void* g_uri;
uint32_t g_depth = 0;
bool g_is_first = true;
#ifdef _WIN64
uint64_t* g_global_stringpool;
uint64_t* g_type_stringpool;
uint64_t* g_key_stringpool;

void initStringPoolIndexArray(uint64_t* array, uint32_t size)
{
	array = new uint64_t[size];
	MEMSET(array, size * TYPE_SIZE(uint64_t));
}

void setStringAddress(void* str_buf, uint64_t* array, uint32_t index)
{
	if (array != NULL)
	{
		array[index] = *((uint64_t*)&str);
	}
}

void* getStringByIndex(uint64_t* array, uint32_t index, uint32_t size)
{
	if (index < 0 || index >= size)
	{
		return NULL;
	}

	return (void*)array[index];
}

void freeStringPoolIndexArray(uint64_t* array, uint32_t size)
{
	if (array != NULL)
	{
		delete[] array;
	}
}
#else
uint32_t* g_global_stringpool = NULL;
uint32_t* g_type_stringpool = NULL;
uint32_t* g_key_stringpool = NULL;

void initStringPoolIndexArray(uint32_t* array, uint32_t size)
{
	array = new uint32_t[size];
	MEMSET(array, size * TYPE_SIZE(uint32_t));
}

void setStringAddress(void* str_buf, uint32_t* array, uint32_t index)
{
	if (array != NULL)
	{
		array[index] = *((uint32_t*)&str_buf);
	}
}

void* getStringByIndex(uint32_t* array, uint32_t index, uint32_t size)
{
	if (index < 0 || index >= size)
	{
		return NULL;
	}

	return (void*)array[index];
}

void freeStringPoolIndexArray(uint32_t* array, uint32_t size)
{
	if (array != NULL)
	{
		delete[] array;
	}
}
#endif

static float complexToFloat(int complex)
{
	return (float)(complex & 0xFFFFFF00) * RADIX_MULTS[(complex >> 4) & 3];
}

void genTableFormat(int depth)
{
	MEMSET(g_table_buf, sizeof(g_table_buf));
	for (int i = 0; i < depth; ++i)
	{
		g_table_buf[i] = '\t';
	}
}

char* getPackage(int data)
{
	return ((data >> 24) == 1) ? "android" : "";
}

char* getAttributeValue(void* array, uint32_t size, Res_value value)
{
	MEMSET(g_attr_buf, ATTR_BUFFER_SIZE);
	switch (value.dataType)
	{
	case value.TYPE_STRING:
	{
		void* data;
#ifdef _WIN64
		data = getStringByIndex((uint64_t*)array, value.data, size);
#else
		data = getStringByIndex((uint32_t*)array, value.data, size);
#endif
		if (g_is_utf8)
		{
			return (char*)data;
		}
		wchar_t* wstr = (wchar_t*)data;
		if (wstr != NULL)
		{
			convertToCharString(g_attr_buf, wcslen(wstr) + 1, wstr);
			return g_attr_buf;
		}
	}
	break;

	case value.TYPE_ATTRIBUTE:
		sprintf_s(g_attr_buf, ATTR_BUFFER_SIZE, "?%s%08X", getPackage(value.data), value.data);
		return g_attr_buf;

	case value.TYPE_REFERENCE:
		sprintf_s(g_attr_buf, ATTR_BUFFER_SIZE, "@%s%08X", getPackage(value.data), value.data);
		return g_attr_buf;

	case value.TYPE_INT_HEX:
		sprintf_s(g_attr_buf, ATTR_BUFFER_SIZE, "0x%08X", value.data);
		return g_attr_buf;

	case value.TYPE_INT_BOOLEAN:
		return value.data == 0 ? "false" : "true";

	case value.TYPE_INT_DEC:
		_itoa_s(value.data, g_attr_buf, 10);
		return g_attr_buf;

	default:
		break;
	}

	if (value.dataType >= value.TYPE_FIRST_COLOR_INT && value.dataType <= value.TYPE_LAST_COLOR_INT)
	{
		sprintf_s(g_attr_buf, ATTR_BUFFER_SIZE, "#%08X", value.data);
		return g_attr_buf;
	}

	if (value.dataType == value.TYPE_DIMENSION) {
		sprintf_s(g_attr_buf, ATTR_BUFFER_SIZE, "%f%s", complexToFloat(value.data), DIMENSION_UNITS[value.data & value.COMPLEX_UNIT_MASK]);
		return g_attr_buf;
	}

	return "";
}

void parseStringPoolContent(FILE* pLog, void* dst_index_buf, uint8_t* string_pool_buf, uint32_t size, uint32_t count)
{
	size_t u16len = 0;
	size_t u8len = 0;
	if (g_is_utf8)
	{
		uint8_t* u8str = string_pool_buf;
		uint16_t hbyte = 0;
		for (uint32_t i = 0; i < count; ++i)
		{
			u16len = decodeUTF8Length(&u8str);
			u8len = decodeUTF8Length(&u8str);
#ifdef _WIN64
			setStringAddress(u8str, (uint64_t*)dst_index_buf, i);
#else
			setStringAddress(u8str, (uint32_t*)dst_index_buf, i);
#endif
			u8str += (u8len + 1);
		}
	}
	else
	{
		uint16_t* str = (uint16_t*)string_pool_buf;
		for (uint32_t i = 0; i < count; ++i)
		{
			u16len = decodeLength(&str);
#ifdef _WIN64
			setStringAddress(str, (uint64_t*)dst_index_buf, i);
#else
			setStringAddress(str, (uint32_t*)dst_index_buf, i);
#endif
			str += (u16len + 1);
		}
	}	
}

void getHeader(FILE* pFile, ResChunk_header* header)
{
	if (pFile == NULL)
	{
		return;
	}

	uint32_t size = TYPE_SIZE(ResChunk_header);
	fread_s(header, size, size, 1, pFile);

	fseek(pFile, -size, SEEK_CUR);
}

void parseStringPool(FILE* pFile, uint32_t* offset)
{
	g_string_pool_seq++;
	ResStringPool_header header;
	uint32_t size = TYPE_SIZE(ResStringPool_header);

	fread_s(&header, size, size, 1, pFile);
	g_is_utf8 = header.flags & header.UTF8_FLAG;
	uint32_t data_size = header.header.size - header.header.headerSize;
	uint8_t* pTemp;

	if (g_is_arsc)
	{
		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "-------StringPool start offset : %08X, count : %d-------", *offset, header.stringCount);
		saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
		MEMSET(g_log_buf, LOG_BUFFER_SIZE);
	}

	if (g_string_pool_seq == 1)
	{
		g_global_string_count = header.stringCount;
#ifdef _WIN64
		g_global_stringpool = new uint64_t[header.stringCount];
		MEMSET(g_global_stringpool, header.stringCount * TYPE_SIZE(uint64_t));
#else
		g_global_stringpool = new uint32_t[header.stringCount];
		MEMSET(g_global_stringpool, header.stringCount * TYPE_SIZE(uint32_t));
#endif
		g_global_chunk = new uint8_t[data_size];
		MEMSET(g_global_chunk, data_size);
		pTemp = g_global_chunk;
	}
	else if (g_string_pool_seq == 2)
	{
		g_type_string_count = header.stringCount;
#ifdef _WIN64
		g_type_stringpool = new uint64_t[header.stringCount];
		MEMSET(g_type_stringpool, header.stringCount * TYPE_SIZE(uint64_t));
#else
		g_type_stringpool = new uint32_t[header.stringCount];
		MEMSET(g_type_stringpool, header.stringCount * TYPE_SIZE(uint32_t));
#endif
		g_type_chunk = new uint8_t[data_size];
		MEMSET(g_type_chunk, data_size);
		pTemp = g_type_chunk;
	}
	else
	{
		g_key_string_count = header.stringCount;
#ifdef _WIN64
		g_key_stringpool = new uint64_t[header.stringCount];
		MEMSET(g_key_stringpool, header.stringCount * TYPE_SIZE(uint64_t));
#else
		g_key_stringpool = new uint32_t[header.stringCount];
		MEMSET(g_key_stringpool, header.stringCount * TYPE_SIZE(uint32_t));
#endif
		g_key_chunk = new uint8_t[data_size];
		MEMSET(g_key_chunk, data_size);
		pTemp = g_key_chunk;
	}

	if (pTemp != NULL)
	{
		fread_s(pTemp, data_size, data_size, 1, pFile);

		uint32_t string_index_array_size = header.stringCount * TYPE_SIZE(ResStringPool_ref);
		//pTemp += string_index_array_size;

		uint32_t style_index_array_size = header.styleCount * TYPE_SIZE(ResStringPool_ref);
		//pTemp += style_index_array_size;

		uint8_t* string_buf = pTemp + header.stringsStart - size;
		if (g_is_arsc)
		{
			saveBufferToFile(string_buf, g_string_pool_seq == 1 ?
				"..\\global_stringpool" : (g_string_pool_seq == 2 ?
					"..\\type_stringpool" : "..\\key_stringpool"),
				data_size - string_index_array_size - style_index_array_size);
		}
		else
		{
			saveBufferToFile(string_buf, "..\\axml_stringpool", data_size - string_index_array_size - style_index_array_size);
		}
		parseStringPoolContent(pLog, 
			g_string_pool_seq == 1 ? g_global_stringpool : (g_string_pool_seq == 2 ? g_type_stringpool : g_key_stringpool),
			string_buf, 
			data_size - string_index_array_size - style_index_array_size, 
			header.stringCount);

		*offset += header.header.size;
	}
}

void parseXMLTreeHeader(FILE* pFile, uint32_t* offset)
{
	ResXMLTree_header header;
	fread_s(&header, TYPE_SIZE(ResXMLTree_header), TYPE_SIZE(ResXMLTree_header), 1, pFile);

	*offset += header.header.headerSize;
	fseek(pFile, *offset, SEEK_SET);
}

void parseXMLMap(FILE* pFile, uint32_t* offset, ResChunk_header* chunk_header)
{
	int target_size = chunk_header->size - chunk_header->headerSize;
	//printf("map offset is %08X\n", *offset);
	uint32_t* map = new uint32_t[target_size / TYPE_SIZE(uint32_t)];
	uint32_t* ori = map;
	MEMSET(map, target_size);
	fread_s(map, target_size, target_size, 1, pFile);

	/*for (int i = 0; i < target_size / 4; ++i)
	{
	cout << hex << ori[i] << endl;
	}*/

	delete[] map;

	*offset += chunk_header->size;
	fseek(pFile, *offset, SEEK_SET);
}

void parseXMLNameSpace(FILE* pFile, uint32_t* offset, ResChunk_header* chunk_header)
{
	ResXMLTree_node node;
	fread_s(&node, sizeof(ResXMLTree_node), sizeof(ResXMLTree_node), 1, pFile);
	/*printf("offset is %08X, namespace header size is %d, chunk size is %d, lineNumber is %d\n", 
		*offset, node.header.headerSize, node.header.size, node.lineNumber);*/

	ResXMLTree_namespaceExt ext;
	fread_s(&ext, sizeof(ResXMLTree_namespaceExt), sizeof(ResXMLTree_namespaceExt), 1, pFile);

	MEMSET(g_log_buf, LOG_BUFFER_SIZE);
	g_prefix = getStringByIndex(g_global_stringpool, ext.prefix.index, g_global_string_count);
	g_uri = getStringByIndex(g_global_stringpool, ext.uri.index, g_global_string_count);
	if (!g_is_utf8)
	{
		char* utf8_prefix = new char[ATTR_BUFFER_SIZE];
		char* utf8_uri = new char[ATTR_BUFFER_SIZE];
		MEMSET(utf8_prefix, ATTR_BUFFER_SIZE);
		MEMSET(utf8_uri, ATTR_BUFFER_SIZE);

		convertToCharString(utf8_prefix, wcslen((wchar_t*)g_prefix) + 1, (wchar_t*)g_prefix);
		convertToCharString(utf8_uri, wcslen((wchar_t*)g_uri) + 1, (wchar_t*)g_uri);

		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "namespace prefix is %s, uri is %s", utf8_prefix, utf8_uri);

		delete[] utf8_prefix;
		delete[] utf8_uri;
	}
	else
	{
		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "namespace prefix is %s, uri is %s", (char*)g_prefix, (char*)g_uri);
	}
	//saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));

	*offset += chunk_header->size;
	fseek(pFile, *offset, SEEK_SET);
}

void parseXMLStartElement(FILE* pFile, uint32_t* offset, ResChunk_header* chunk_header)
{
	ResXMLTree_node node;
	fread_s(&node, sizeof(ResXMLTree_node), sizeof(ResXMLTree_node), 1, pFile);
	/*printf("start offset is %08X, element header size is %d, chunk size is %d, lineNumber is %d\n",
		*offset, node.header.headerSize, node.header.size, node.lineNumber);*/
	
	genTableFormat(g_depth++);
	char* utf8_prefix = new char[ATTR_BUFFER_SIZE];
	char* utf8_uri = new char[ATTR_BUFFER_SIZE];
	char* utf8_name = new char[ATTR_BUFFER_SIZE];
	MEMSET(utf8_prefix, ATTR_BUFFER_SIZE);
	MEMSET(utf8_uri, ATTR_BUFFER_SIZE);
	MEMSET(utf8_name, ATTR_BUFFER_SIZE);

	ResXMLTree_attrExt ext;
	fread_s(&ext, sizeof(ResXMLTree_attrExt), sizeof(ResXMLTree_attrExt), 1, pFile);
	if (!g_is_utf8)
	{
		convertToCharString(utf8_prefix, wcslen((wchar_t*)g_prefix) + 1, (wchar_t*)g_prefix);
		convertToCharString(utf8_uri, wcslen((wchar_t*)g_uri) + 1, (wchar_t*)g_uri);
		wchar_t* name = (wchar_t*)getStringByIndex(g_global_stringpool, ext.name.index, g_global_string_count);
		convertToCharString(utf8_name, wcslen(name) + 1, name);
		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "%s<%s", g_table_buf, utf8_name);
	}
	else
	{
		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "%s<%s", g_table_buf, (char*)getStringByIndex(g_global_stringpool, ext.name.index, g_global_string_count));
	}

	saveLogInformation(pLog, g_log_buf, strlen(g_log_buf));
	memset(g_log_buf, 0, LOG_BUFFER_SIZE);

	if (g_is_first)
	{
		if (g_is_utf8)
		{
			sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "\txmlns:%s=\"%s\"", (char*)g_prefix, (char*)g_uri);
		}
		else
		{
			sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "\txmlns:%s=\"%s\"", utf8_prefix, utf8_uri);
		}
		saveLogInformation(pLog, g_log_buf, strlen(g_log_buf));
		g_is_first = false;
	}

	if (ext.attributeCount > 0)
	{
		int size = ext.attributeCount * sizeof(ResXMLTree_attribute);
		ResXMLTree_attribute* attribute = new ResXMLTree_attribute[ext.attributeCount];
		ResXMLTree_attribute* pTmp = attribute;
		MEMSET(attribute, size);
		fread_s(attribute, size, size, 1, pFile);
		genTableFormat(g_depth);
		for (int i = 0; i < ext.attributeCount; ++i)
		{
			if (i == 0)
			{
				saveLogInformationAutoLine(pLog, "", 0);
			}
			MEMSET(g_log_buf, LOG_BUFFER_SIZE);
			MEMSET(utf8_name, ATTR_BUFFER_SIZE);
			ResXMLTree_attribute attr = *pTmp++;
			uint32_t empty = 0xFFFFFFFF;
			if (attr.ns.index != empty)
			{
				if (g_is_utf8)
				{
					sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "%s%s:%s=\"%s\"", g_table_buf, (char*)g_prefix,
						(char*)getStringByIndex(g_global_stringpool, attr.name.index, g_global_string_count),
						getAttributeValue(g_global_stringpool, g_global_string_count, attr.typedValue));
				}
				else
				{
					wchar_t* name = (wchar_t*)getStringByIndex(g_global_stringpool, attr.name.index, g_global_string_count);
					convertToCharString(utf8_name, wcslen(name) + 1, name);
					sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "%s%s:%s=\"%s\"", g_table_buf, utf8_prefix, utf8_name,
						getAttributeValue(g_global_stringpool, g_global_string_count, attr.typedValue));
				}
			}
			else
			{
				if (g_is_utf8)
				{
					sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "%s%s=\"%s\"", g_table_buf, (char*)getStringByIndex(g_global_stringpool, attr.name.index, g_global_string_count),
						getAttributeValue(g_global_stringpool, g_global_string_count, attr.typedValue));
				}
				else
				{
					wchar_t* name = (wchar_t*)getStringByIndex(g_global_stringpool, attr.name.index, g_global_string_count);
					convertToCharString(utf8_name, wcslen(name) + 1, name);
					sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "%s%s=\"%s\"", g_table_buf, utf8_name,
						getAttributeValue(g_global_stringpool, g_global_string_count, attr.typedValue));
				}
			}
			if (i == ext.attributeCount - 1)
			{
				saveLogInformation(pLog, g_log_buf, strlen(g_log_buf));
			}
			else
			{
				saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
			}
		}
		delete[] utf8_prefix;
		delete[] utf8_uri;
		delete[] utf8_name;
		delete[] attribute;
	}
	saveLogInformationAutoLine(pLog, ">", strlen(">"));
	*offset += chunk_header->size;
	fseek(pFile, *offset, SEEK_SET);
}

void parseXMLEndElement(FILE* pFile, uint32_t* offset, ResChunk_header* chunk_header)
{
	ResXMLTree_node node;
	fread_s(&node, sizeof(ResXMLTree_node), sizeof(ResXMLTree_node), 1, pFile);
	/*printf("end element offset is %08X, element header size is %d, chunk size is %d, lineNumber is %d\n",
		*offset, node.header.headerSize, node.header.size, node.lineNumber);*/

	ResXMLTree_endElementExt ext;
	fread_s(&ext, sizeof(ResXMLTree_endElementExt), sizeof(ResXMLTree_endElementExt), 1, pFile);

	genTableFormat(--g_depth);

	char* utf8_name = new char[ATTR_BUFFER_SIZE];
	MEMSET(utf8_name, ATTR_BUFFER_SIZE);
	void* name = getStringByIndex(g_global_stringpool, ext.name.index, g_global_string_count);
	if (g_is_utf8)
	{
		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "%s</%s>", g_table_buf, (char*)name);
	}
	else
	{
		convertToCharString(utf8_name, wcslen((wchar_t*)name) + 1, (wchar_t*)name);
		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "%s</%s>", g_table_buf, utf8_name);
	}
	delete[] utf8_name;
	saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
	*offset += chunk_header->size;
	fseek(pFile, *offset, SEEK_SET);
}

void parseTableType(FILE* pFile, uint32_t* offset)
{
	ResTable_header table_header;
	uint32_t table_header_size = TYPE_SIZE(ResTable_header);
	fread_s(&table_header, table_header_size, table_header_size, 1, pFile);
	*offset += table_header_size;
}

void parseTablePackage(FILE* pFile, uint32_t* offset)
{
	ResTable_package header;
	uint32_t size = TYPE_SIZE(ResTable_package);
	fread_s(&header, size, size, 1, pFile);

	sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "-------package start offset : %08X, size : %d-------", *offset, header.header.size);
	saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));

	char* packageName = new char[128];
	MEMSET(packageName, 128);
	convertToCharString(packageName, wcslen((wchar_t*)header.name) + 1, (wchar_t*)header.name);
	MEMSET(g_log_buf, LOG_BUFFER_SIZE);
	sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "\t\t\t\tpackage name is : %s, typeStrings offset : %d, lastPublicType : %d, keyStrings offset : %d",
		packageName,
		header.typeStrings, header.lastPublicType, header.keyStrings);
	saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
	MEMSET(g_log_buf, LOG_BUFFER_SIZE);
	delete[] packageName;

	if (header.typeStrings > sizeof(ResTable_package))
	{
		fseek(pFile, header.typeStrings - sizeof(ResTable_package), SEEK_CUR);
	}
	*offset += header.typeStrings;
}

void parseTableSpec(FILE* pFile, uint32_t* offset)
{
	ResTable_typeSpec spec_header;
	uint32_t size = TYPE_SIZE(ResTable_typeSpec);
	fread_s(&spec_header, size, size, 1, pFile);

	MEMSET(g_log_buf, LOG_BUFFER_SIZE);
	sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "-------spec start offset : %08X, id : %d, chunk size : %d, entry count : %d-------", 
		*offset,
		spec_header.id, 
		spec_header.header.size, 
		spec_header.entryCount);
	saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
	MEMSET(g_log_buf, LOG_BUFFER_SIZE);

	*offset += spec_header.header.size;
	fseek(pFile, *offset, SEEK_SET);
}

void parseTableTypeType(FILE* pFile, uint32_t* offset, ResChunk_header* chunk_header)
{
	ResTable_type table_type_header;
	uint8_t* real = new uint8_t[chunk_header->headerSize];
	fread_s(real, chunk_header->headerSize, chunk_header->headerSize, 1, pFile);
	memcpy(&table_type_header, real, TYPE_SIZE(ResTable_type));
	delete[] real;

	MEMSET(g_log_buf, LOG_BUFFER_SIZE);
	sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "-------type start offset : %08X, chunk size : %d, entry count : %d, imsi : %d, locale : %d-------",
		*offset, table_type_header.header.size, table_type_header.entryCount,
		table_type_header.config.imsi, table_type_header.config.locale);
	saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));

	uint32_t* entrys = new uint32_t[table_type_header.entryCount];
	MEMSET(entrys, table_type_header.entryCount * TYPE_SIZE(uint32_t));
	fread_s(entrys, table_type_header.entryCount * TYPE_SIZE(uint32_t), table_type_header.entryCount * TYPE_SIZE(uint32_t), 1, pFile);
	uint32_t item_size = TYPE_SIZE(ResTable_entry) + TYPE_SIZE(ResTable_map);
	uint32_t item_map_size = TYPE_SIZE(ResTable_map_entry) + TYPE_SIZE(ResTable_map);
	uint32_t item_no_map_size = TYPE_SIZE(ResTable_entry) + TYPE_SIZE(Res_value);
	uint32_t entry_array_size = table_type_header.header.size - table_type_header.entriesStart;
	uint32_t valid_entry_count = 0;
	if (table_type_header.entryCount == 1)
	{
		item_size = entry_array_size;
		valid_entry_count = 1;
	}
	else if (table_type_header.entryCount > 0)
	{
		uint32_t offset = 0x80000000;
		bool is_calculated = false;
		for (uint32_t i = 0; i < table_type_header.entryCount; ++i)
		{
			if (*(entrys + i) == table_type_header.NO_ENTRY)
			{
				continue;
			}

			++valid_entry_count;
			if (!is_calculated)
			{
				if (offset != 0x80000000)
				{
					item_size = *(entrys + i) - offset;
					is_calculated = true;
				}
				else
				{
					offset = *(entrys + i);
				}
			}
		}

		if (valid_entry_count == 1)
		{
			item_size = entry_array_size;
		}
		else if (valid_entry_count == table_type_header.entryCount)
		{
			item_size = (*(entrys + table_type_header.entryCount - 1) - *(entrys + table_type_header.entryCount - 2));
		}

		MEMSET(g_log_buf, LOG_BUFFER_SIZE);
		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "-------entry item size : %d, entry array total size : %d-------", item_size, entry_array_size);

		saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
	}
	delete[] entrys;

	bool is_no_map_entry = item_size == item_no_map_size;
	bool is_map_enery = item_size == item_map_size;
	uint8_t* pTemp = new uint8_t[item_size];

	ResTable_entry entry;
	for (uint32_t i = 0; i < valid_entry_count; ++i)
	{
		MEMSET(pTemp, item_size);
		fread_s(pTemp, item_size, item_size, 1, pFile);
		memcpy(&entry, pTemp, sizeof(ResTable_entry));
		MEMSET(g_log_buf, LOG_BUFFER_SIZE);
		sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "\t\t\t\tentry index : %d, size : %d, flag : %d, key : %s-------", 
			i, entry.size, entry.flags, (char*)getStringByIndex(g_key_stringpool, entry.key.index, g_key_string_count));
		saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
		if (entry.flags == entry.FLAG_COMPLEX)
		{
			if (entry.size == sizeof(ResTable_map_entry))
			{
				ResTable_map_entry map_entry;
				memcpy(&map_entry, pTemp, sizeof(ResTable_map_entry));
				fseek(pFile, -item_size, SEEK_CUR);
				uint32_t entry_size = map_entry.count * sizeof(ResTable_map) + sizeof(ResTable_map_entry);
				uint8_t* p_entry = new uint8_t[entry_size];
				MEMSET(p_entry, entry_size);
				fread_s(p_entry, entry_size, entry_size, 1, pFile);

				uint8_t* p_map_start = p_entry + sizeof(ResTable_map_entry);
				for (uint32_t j = 0; j < map_entry.count; ++j)
				{
					ResTable_map map;
					memcpy(&map, p_map_start + (j * sizeof(ResTable_map)), sizeof(ResTable_map));
					MEMSET(g_log_buf, LOG_BUFFER_SIZE);
					sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "\t\t\t\t\t\tident : %08X, type name : %s, value type : %d, value size : %d, value data : %s",
						map.name.ident, (char*)getStringByIndex(g_type_stringpool, (map.name.ident & 0x00FF0000) >> 16, g_type_string_count), map.value.dataType,
						map.value.size, getAttributeValue(g_global_stringpool, g_global_string_count, map.value));
					saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
				}

				delete[] p_entry;
			}
			else
			{
				MEMSET(g_log_buf, LOG_BUFFER_SIZE);
				ResTable_map map;
				memcpy(&map, pTemp + sizeof(ResTable_entry), sizeof(ResTable_map));
				sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "\t\t\t\tident : %08X, type name : %s, value type : %d, value size : %d, value data : %s", 
					map.name.ident, (char*)getStringByIndex(g_type_stringpool, (map.name.ident & 0x00FF0000) >> 16, g_type_string_count), map.value.dataType,
					map.value.size, getAttributeValue(g_global_stringpool, g_global_string_count, map.value));
				saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
			}
		}
		else
		{
			Res_value value;
			memcpy(&value, pTemp + sizeof(ResTable_entry), sizeof(Res_value));
			MEMSET(g_log_buf, LOG_BUFFER_SIZE);
			sprintf_s(g_log_buf, LOG_BUFFER_SIZE, "\t\t\t\tvalue index : %d, size : %d, type : %d, data : %s", 
				i, value.size, value.dataType, getAttributeValue(g_global_stringpool, g_global_string_count, value));
			saveLogInformationAutoLine(pLog, g_log_buf, strlen(g_log_buf));
		}
	}

	delete[] pTemp;

	*offset += table_type_header.header.size;
	fseek(pFile, *offset, SEEK_SET);
}

void deleteArray(void** array)
{
	if (*array != NULL)
	{
		delete[] *array;
		*array = NULL;
	}
}

void parseResourceFile(const char* src, const char* dst)
{
	FILE* pSrc = NULL;
	errno_t err = fopen_s(&pSrc, src, "rb");
	uint32_t offset = 0;
	if (0 == err)
	{
		openLogFile(&pLog, dst, "wb+");
		ResChunk_header chunk_header;
		getHeader(pSrc, &chunk_header);
		g_file_size = chunk_header.size;
		printf("g_file_size : %d\n", g_file_size);
		uint32_t chunk_header_size = TYPE_SIZE(ResChunk_header);
		while (offset < g_file_size)
		{
			getHeader(pSrc, &chunk_header);
			switch (chunk_header.type)
			{
			case RES_XML_TYPE:
				parseXMLTreeHeader(pSrc, &offset);
				saveLogInformationAutoLine(pLog, (void*)XML_HEADER, strlen(XML_HEADER));
				break;

			case RES_XML_RESOURCE_MAP_TYPE:
				parseXMLMap(pSrc, &offset, &chunk_header);
				break;

			case RES_XML_START_NAMESPACE_TYPE:
			case RES_XML_END_NAMESPACE_TYPE:
				parseXMLNameSpace(pSrc, &offset, &chunk_header);
				break;

			case RES_XML_START_ELEMENT_TYPE:
				parseXMLStartElement(pSrc, &offset, &chunk_header);
				break;

			case RES_XML_END_ELEMENT_TYPE:
				parseXMLEndElement(pSrc, &offset, &chunk_header);
				break;

			case RES_TABLE_TYPE:
				g_is_arsc = true;
				parseTableType(pSrc, &offset);
				break;

			case RES_STRING_POOL_TYPE:
				parseStringPool(pSrc, &offset);
				break;

			case RES_TABLE_PACKAGE_TYPE:
				parseTablePackage(pSrc, &offset);
				break;

			case RES_TABLE_TYPE_SPEC_TYPE:
				parseTableSpec(pSrc, &offset);
				break;

			case RES_TABLE_TYPE_TYPE:
				parseTableTypeType(pSrc, &offset, &chunk_header);
				break;

			default:
				break;
			}
			MEMSET(&chunk_header, chunk_header_size);
		}

		printf("%d : %d\n", g_file_size, offset);
		g_string_pool_seq = 0;
		g_is_arsc = false;
		g_depth = 0;

		deleteArray((void**)&g_global_chunk);
		deleteArray((void**)&g_type_chunk);
		deleteArray((void**)&g_key_chunk);

		deleteArray((void**)&g_global_stringpool);
		deleteArray((void**)&g_type_stringpool);
		deleteArray((void**)&g_key_stringpool);

		closeLogFile(pLog);

		fclose(pSrc);
	}
}